package socket;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

/**
 * 聊天室客户端
 */
public class Client {
    /*
     * java.net.Socket 套接字,原意是插座
     * Socket封装了TCP协议的通讯细节,我们使用这个工具就可以与远端计算机建立TCP链接,
     * 并基于一堆流的IO操作完成与远端计算机的数据交换
     */
    private Socket socket;

    /*
     * 初始化客户端
     */
    public Client() {
        try {
            System.out.println("正在链接服务器...");
            /*
             * 实例化Socket时,需要传入两个参数:
             * 参数1(String):远端计算机的地址信息(IP)
             *              本机地址IP可以选择如下:
             *                  localhost(域名)
             *                  127.0.0.1
             * 参数2(int):远端计算机打开的服务端口
             *           此端口值必须要和服务器端占用的端口保持一致
             *
             */
            socket = new Socket("localhost", 8088);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
     * 客户端开始工作的方法
     */
    public void start() {
        try {
            //启动一个线程来读取服务器端发送的信息
            ServerHandler handler = new ServerHandler();
            Thread t = new Thread(handler);
            //将子线程设置为守护线程,当主线程结束时,也会一同关闭
            t.setDaemon(true);
            t.start();
            /*
             * 通过Socket的方法:
             * OutputStream getOutputStream()
             * 获取的字节输出流写出的字节会通过网络发送给链接的远端计算机
             */
            OutputStream out = socket.getOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);
            BufferedWriter bw = new BufferedWriter(osw);
            PrintWriter pw = new PrintWriter(bw, true);
            Scanner scanner = new Scanner(System.in);//创建控制台扫描器
            while (true) {//一直接收控制输入的内容
                String line = scanner.nextLine();//获取本次在控制输入的内容
                if ("exit".equalsIgnoreCase(line)) {//判断输入的内容是否是exit
                    break;//如果是,就跳出循环
                }
                pw.println(line);//如果输入的不是exit,就将内容发送给服务器
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();//与远端计算机断开连接,并且进行TCP的挥手,同时关闭连接的流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //项目的主入口
    public static void main(String[] args) {
        Client client = new Client();
        client.start();
    }

    /*
     * 该线程负责读取服务器端发送的消息
     */
    private class ServerHandler implements Runnable {
        @Override
        public void run() {
            //通过socket获取输入流读取服务器发送的消息
            try {//线程的run方法中,不允许使用throws声明异常异常
                InputStream in = socket.getInputStream();
                InputStreamReader isr =
                        new InputStreamReader(in, StandardCharsets.UTF_8);
                BufferedReader br = new BufferedReader(isr);
                //创建流之后,继续循环读取服务器发送的信息
                String line;
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                //打印异常代码删除,因为只有客户端异常断开时,才会报,所以不需要看
            }

        }
    }
}
